/*!
 * Ext JS Library 3.2.1
 * Copyright(c) 2006-2010 Ext JS, Inc.
 * licensing@extjs.com
 * http://www.extjs.com/license
 */
Ext.ns('Ext.ux');
/**
 * @class Ext.ux.TabScrollerMenu
 * @extends Object 
 * Plugin (ptype = 'tabscrollermenu') for adding a tab scroller menu to tabs.
 * @constructor 
 * @param {Object} config Configuration options
 * @ptype tabscrollermenu
 */
Ext.ux.TabScrollerMenu =  Ext.extend(Object, {
    /**
     * @cfg {Number} pageSize How many items to allow per submenu.
     */
	pageSize       : 10,
    /**
     * @cfg {Number} maxText How long should the title of each {@link Ext.menu.Item} be.
     */
	maxText        : 15,
    /**
     * @cfg {String} menuPrefixText Text to prefix the submenus.
     */    
	menuPrefixText : 'Items',
	constructor    : function(config) {
		config = config || {};
		Ext.apply(this, config);
	},
    //private
	init : function(tabPanel) {
		Ext.apply(tabPanel, this.parentOverrides);
		
		tabPanel.tabScrollerMenu = this;
		var thisRef = this;
		
		tabPanel.on({
			render : {
				scope  : tabPanel,
				single : true,
				fn     : function() { 
					var newFn = tabPanel.createScrollers.createSequence(thisRef.createPanelsMenu, this);
					tabPanel.createScrollers = newFn;
				}
			}
		});
	},
	// private && sequeneced
	createPanelsMenu : function() {
		var h = this.stripWrap.dom.offsetHeight;
		
		//move the right menu item to the left 18px
		var rtScrBtn = this.header.dom.firstChild;
		Ext.fly(rtScrBtn).applyStyles({
			right : '18px'
		});
		
		var stripWrap = Ext.get(this.strip.dom.parentNode);
		stripWrap.applyStyles({
			 'margin-right' : '36px'
		});
		
		// Add the new righthand menu
		var scrollMenu = this.header.insertFirst({
			cls:'x-tab-tabmenu-right'
		});
		scrollMenu.setHeight(h);
		scrollMenu.addClassOnOver('x-tab-tabmenu-over');
		scrollMenu.on('click', this.showTabsMenu, this);	
		
		this.scrollLeft.show = this.scrollLeft.show.createSequence(function() {
			scrollMenu.show();												 						 
		});
		
		this.scrollLeft.hide = this.scrollLeft.hide.createSequence(function() {
			scrollMenu.hide();								
		});
		
	},
    /**
     * Returns an the current page size (this.pageSize);
     * @return {Number} this.pageSize The current page size.
     */
	getPageSize : function() {
		return this.pageSize;
	},
    /**
     * Sets the number of menu items per submenu "page size".
     * @param {Number} pageSize The page size
     */
    setPageSize : function(pageSize) {
		this.pageSize = pageSize;
	},
    /**
     * Returns the current maxText length;
     * @return {Number} this.maxText The current max text length.
     */
    getMaxText : function() {
		return this.maxText;
	},
    /**
     * Sets the maximum text size for each menu item.
     * @param {Number} t The max text per each menu item.
     */
    setMaxText : function(t) {
		this.maxText = t;
	},
    /**
     * Returns the current menu prefix text String.;
     * @return {String} this.menuPrefixText The current menu prefix text.
     */
	getMenuPrefixText : function() {
		return this.menuPrefixText;
	},
    /**
     * Sets the menu prefix text String.
     * @param {String} t The menu prefix text.
     */    
	setMenuPrefixText : function(t) {
		this.menuPrefixText = t;
	},
	// private && applied to the tab panel itself.
	parentOverrides : {
		// all execute within the scope of the tab panel
		// private	
		showTabsMenu : function(e) {		
			if  (this.tabsMenu) {
				this.tabsMenu.destroy();
                this.un('destroy', this.tabsMenu.destroy, this.tabsMenu);
                this.tabsMenu = null;
			}
            this.tabsMenu =  new Ext.menu.Menu();
            this.on('destroy', this.tabsMenu.destroy, this.tabsMenu);

            this.generateTabMenuItems();

            var target = Ext.get(e.getTarget());
			var xy     = target.getXY();
//
			//Y param + 24 pixels
			xy[1] += 24;
			
			this.tabsMenu.showAt(xy);
		},
		// private	
		generateTabMenuItems : function() {
			var curActive  = this.getActiveTab();
			var totalItems = this.items.getCount();
			var pageSize   = this.tabScrollerMenu.getPageSize();
			
			
			if (totalItems > pageSize)  {
				var numSubMenus = Math.floor(totalItems / pageSize);
				var remainder   = totalItems % pageSize;
				
				// Loop through all of the items and create submenus in chunks of 10
				for (var i = 0 ; i < numSubMenus; i++) {
					var curPage = (i + 1) * pageSize;
					var menuItems = [];
					
					
					for (var x = 0; x < pageSize; x++) {				
					  var 	index = x + curPage - pageSize;
						var item = this.items.get(index);
						menuItems.push(this.autoGenMenuItem(item));
					}
					
					this.tabsMenu.add({
						text : this.tabScrollerMenu.getMenuPrefixText() + ' '  + (curPage - pageSize + 1) + ' - ' + curPage,
						menu : menuItems
					});
					
				}
				// remaining items
				if (remainder > 0) {
					var start = numSubMenus * pageSize;
					menuItems = [];
					for (var i = start ; i < totalItems; i ++ ) {					
						var item = this.items.get(i);
						menuItems.push(this.autoGenMenuItem(item));
					}
					
					this.tabsMenu.add({
						text : this.tabScrollerMenu.menuPrefixText  + ' ' + (start + 1) + ' - ' + (start + menuItems.length),
						menu : menuItems
					});

				}
			}
			else {
				this.items.each(function(item) {
					if (item.id != curActive.id && !item.hidden) {
                        this.tabsMenu.add(this.autoGenMenuItem(item));
					}
				}, this);
			}
		},
		// private
		autoGenMenuItem : function(item) {
			var maxText = this.tabScrollerMenu.getMaxText();
			var text    = Ext.util.Format.ellipsis(item.title, maxText);
			
			return {
				text      : text,
				handler   : this.showTabFromMenu,
				scope     : this,
				disabled  : item.disabled,
				tabToShow : item,
				iconCls   : item.iconCls
			}
		
		},
		// private
		showTabFromMenu : function(menuItem) {
			this.setActiveTab(menuItem.tabToShow);
		}	
	}	
});

Ext.reg('tabscrollermenu', Ext.ux.TabScrollerMenu);
Ext.ux.TabCloseMenu = Ext.extend(Object, {
    /**
     * @cfg {String} closeTabText
     * The text for closing the current tab. Defaults to <tt>'Close Tab'</tt>.
     */
    closeTabText: '关闭当前标签',

    /**
     * @cfg {String} closeOtherTabsText
     * The text for closing all tabs except the current one. Defaults to <tt>'Close Other Tabs'</tt>.
     */
    closeOtherTabsText: '关闭其它标签',
    
    /**
     * @cfg {Boolean} showCloseAll
     * Indicates whether to show the 'Close All' option. Defaults to <tt>true</tt>. 
     */
    showCloseAll: true,

    /**
     * @cfg {String} closeAllTabsText
     * <p>The text for closing all tabs. Defaults to <tt>'Close All Tabs'</tt>.
     */
    closeAllTabsText: '关闭所有标签',
    
    constructor : function(config){
        Ext.apply(this, config || {});
    },

    //public
    init : function(tabs){
        this.tabs = tabs;
        tabs.on({
            scope: this,
            contextmenu: this.onContextMenu,
            destroy: this.destroy
        });
    },
    
    destroy : function(){
        Ext.destroy(this.menu);
        delete this.menu;
        delete this.tabs;
        delete this.active;    
    },

    // private
    onContextMenu : function(tabs, item, e){
        this.active = item;
        var m = this.createMenu(),
            disableAll = true,
            disableOthers = true,
            closeAll = m.getComponent('closeall');
        
        m.getComponent('close').setDisabled(!item.closable);
        tabs.items.each(function(){
            if(this.closable){
                disableAll = false;
                if(this != item){
                    disableOthers = false;
                    return false;
                }
            }
        });
        m.getComponent('closeothers').setDisabled(disableOthers);
        if(closeAll){
            closeAll.setDisabled(disableAll);
        }
        
        e.stopEvent();
        m.showAt(e.getPoint());
    },
    
    createMenu : function(){
        if(!this.menu){
            var items = [{
                itemId: 'close',
                text: this.closeTabText,
                scope: this,
                handler: this.onClose
            }];
            if(this.showCloseAll){
                items.push('-');
            }
            items.push({
                itemId: 'closeothers',
                text: this.closeOtherTabsText,
                scope: this,
                handler: this.onCloseOthers
            });
            if(this.showCloseAll){
                items.push({
                    itemId: 'closeall',
                    text: this.closeAllTabsText,
                    scope: this,
                    handler: this.onCloseAll
                });
            }
            this.menu = new Ext.menu.Menu({
                items: items
            });
        }
        return this.menu;
    },
    
    onClose : function(){
        this.tabs.remove(this.active);
    },
    
    onCloseOthers : function(){
        this.doClose(true);
    },
    
    onCloseAll : function(){
        this.doClose(false);
    },
    
    doClose : function(excludeActive){
        var items = [];
        this.tabs.items.each(function(item){
            if(item.closable){
                if(!excludeActive || item != this.active){
                    items.push(item);
                }    
            }
        }, this);
        Ext.each(items, function(item){
            this.tabs.remove(item);
        }, this);
    }
});

Ext.preg('tabclosemenu', Ext.ux.TabCloseMenu);

Ext.ux.ExcelCellSelectionModel = function(config){
    Ext.apply(this, config);
	this.selection 				= null;
	this.mouseSelectionEnable	= false;
    this.firstSelectedCell		= [0,0];
    this.selectedCellRange		= [0,0,0,0];
    this.addEvents(
        /**
	     * @event beforecellselect
	     * Fires before a cell is selected.
	     * @param {SelectionModel} this
	     * @param {Number} rowIndex The selected row index
	     * @param {Number} colIndex The selected cell index
	     */
	    "beforecellselect",
        /**
	     * @event cellselect
	     * Fires when a cell is selected.
	     * @param {SelectionModel} this
	     * @param {Number} rowIndex The selected row index
	     * @param {Number} colIndex The selected cell index
	     */
	    "cellselect",
        /**
	     * @event selectionchange
	     * Fires when the active selection changes.
	     * @param {SelectionModel} this
	     * @param {Object} selection null for no selection or an object (o) with two properties
	        <ul>
	        <li>o.record: the record object for the row the selection is in</li>
	        <li>o.cell: An array of [rowIndex, columnIndex]</li>
	        </ul>
	     */
	    "selectionchange"
    );

    Ext.ux.ExcelCellSelectionModel.superclass.constructor.call(this);
};

Ext.extend(Ext.ux.ExcelCellSelectionModel, Ext.grid.CellSelectionModel,  { 
	
   /** @ignore */
    initEvents : function(){
        this.grid.on("cellmouseover", this.handleMouseOver, this);
        this.grid.on("mouseup", this.handleMouseUp, this);
        this.grid.on("cellmousedown", this.handleMouseDown, this);
        this.grid.getGridEl().on(Ext.isIE || Ext.isSafari3 ? "keydown" : "keypress", this.handleKeyDown, this);
        var view = this.grid.view;
        view.on("refresh", this.onViewChange, this);
        view.on("rowupdated", this.onRowUpdated, this);
        view.on("beforerowremoved", this.clearSelections, this);
        view.on("beforerowsinserted", this.clearSelections, this);
        if(this.grid.isEditor){
            this.grid.on("beforeedit", this.beforeEdit,  this);
        }
    },
   
    /**
     * Clears all selections.
     * @param {Boolean} true to prevent the gridview from being notified about the change.
     */
    clearSelections : function(preventNotify){   	
        var s = this.selection;        
        if(s){
        	this.deSelectCellRange();
            if(preventNotify !== true){
                this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
            }
            this.selection = null;
            this.fireEvent("selectionchange", this, null);
        }
    }, 
    handleMouseOver:function(g, row, cell, e){       
        if(this.mouseSelectionEnable){
        	this.clearSelections();
	        this.select(row, cell);	        
	    	this.makeCellRange(row, cell, this.firstSelectedCell[0], this.firstSelectedCell[1]);
	    	this.selectCellRange();
        }        
    },
    handleMouseUp:function(g, row, cell, e){
    	//alert("handleMouseUp")
    	this.mouseSelectionEnable = false;       
    },
    /** @ignore */
    handleMouseDown : function(g, row, cell, e){   
    	//alert("handleMouseDown")
        if(e.button !== 0 || this.isLocked()){
            return;
        };
        this.mouseSelectionEnable = true;
        this.clearSelections();
        this.select(row, cell);        
        if(!e.shiftKey){
        	this.firstSelectedCell	= [row, cell];
        }
    	this.makeCellRange(row, cell, this.firstSelectedCell[0], this.firstSelectedCell[1]);
    	this.selectCellRange();
    },

    /**
     * Selects a cell.
     * @param {Number} rowIndex
     * @param {Number} collIndex
     */
    select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
        if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){           
            r = r || this.grid.store.getAt(rowIndex);
            this.selection = {
                record : r,
                cell : [rowIndex, colIndex]
            };            
            if(!preventViewNotify){
                var v = this.grid.getView();
                v.onCellSelect(rowIndex, colIndex);
                if(preventFocus !== true){
                    v.focusCell(rowIndex, colIndex);
                }
            }
            this.fireEvent("cellselect", this, rowIndex, colIndex);
            this.fireEvent("selectionchange", this, this.selection);
        }
    },

    handleKeyDown : function(e, cellElement, abc, abc2){
		
        if(!e.isNavKeyPress() && !e.shiftKey){			
			if(this.grid.stopAutoEditing !== true ){
				var g = this.grid;			
				if( g.isEditor && !g.editing ){
					g.startEditing(this.getSelectedCell()[0], this.getSelectedCell()[1]);
					e.stopEvent();				
				}
			}
            return;
        }
        var g = this.grid, s = this.selection;
        if(!s){
            e.stopEvent();
            var cell = g.walkCells(0, 0, 1, this.isSelectable,  this);
            if(cell){
                this.select(cell[0], cell[1]);
            }
            return;
        }
        var sm = this;
        var walk = function(row, col, step){
            return g.walkCells(row, col, step, sm.isSelectable,  sm);
        };
        var k = e.getKey(), r = s.cell[0], c = s.cell[1];
        var newCell;

        switch(k){
             case e.TAB:
                 if(e.shiftKey){
                     newCell = walk(r, c-1, -1);
                 }else{
                     newCell = walk(r, c+1, 1);
                 }
             break;
             case e.DOWN:
                 newCell = walk(r+1, c, 1);
             break;
             case e.UP:
                 newCell = walk(r-1, c, -1);
             break;
             case e.RIGHT:
                 newCell = walk(r, c+1, 1);
             break;
             case e.LEFT:
                 newCell = walk(r, c-1, -1);
             break;
             case e.ENTER:
			 	//alert(g.editing)
                 if(g.isEditor && !g.editing){
                    g.startEditing(r, c);
					this.grid.editing=true;
                    e.stopEvent();
                    return;
                }
             break;
        };
        if(newCell){
        	this.clearSelections();
            this.select(newCell[0], newCell[1]);
            /*Ext.example.msg('',newCell[0]+":::"+newCell[1]+","+this.firstSelectedCell[0]+":::"+this.firstSelectedCell[1]);*/
            if(!e.shiftKey){
            	this.firstSelectedCell = newCell; 	
            }
            this.makeCellRange(newCell[0], newCell[1], this.firstSelectedCell[0], this.firstSelectedCell[1]); 
			this.selectCellRange();	
            e.stopEvent();
        }
    },
    makeCellRange:function(row1, col1, row2, col2){
    	if(row1 > row2){
        	temp_row = row1;
        	row1 = row2;
        	row2 = temp_row;
        }
        if(col1 > col2){
        	temp_col = col1;
        	col1 = col2;
        	col2 = temp_col;
        }
        this.selectedCellRange = [row1, col1, row2, col2];
    },
    
    selectCellRange:function(){
   	   var cr = this.selectedCellRange;
       var row1 = cr[0], col1 = cr[1], row2 = cr[2], col2=cr[3];
        for(var r = row1; r<= row2; r++){
        	for(var c = col1; c<= col2; c++){
        	  this.grid.view.onCellSelect(r, c);   	  
        	}
        }
    },
    getSelectedCellRange:function(){
    	return this.selectedCellRange;    
    },
    deSelectCellRange:function(){
   	   var cr = this.selectedCellRange;
       var row1 = cr[0], col1 = cr[1], row2 = cr[2], col2=cr[3];
       for(var r = row1; r<= row2; r++){
		for(var c = col1; c<= col2; c++){
		  this.grid.view.onCellDeselect(r, c);
		}
       }
    }
});
/**
 * @class Ext.ux.EditorPasteCopyGridPanel
 * Version: 1.4
 * Author: Surinder singh http://www.sencha.com/forum/member.php?75710-Surinder-singh, surinder83singh@gmail.com
 * changes: 1) added the block fill feature.
 			2) support for auto editing on any non-navigation key press (feature demanded by jackpan http://www.sencha.com/forum/member.php?181839-jackpan). 
 *
 */
Ext.ux.EditorPasteCopyGridPanel = Ext.extend(Ext.grid.EditorGridPanel, {

	 /**
     * @cfg {Number} clicksToEdit
     * <p>The number of clicks on a cell required to display the cell's editor (defaults to 2).</p>
     * <p>Setting this option to 'auto' means that mousedown <i>on the selected cell</i> starts
     * editing that cell.</p>
     */
 	clicksToEdit:'auto',
 	
 	initComponent : function(){
 		Ext.ux.EditorPasteCopyGridPanel.superclass.initComponent.call(this);
 		/*make sure that selection modal is ExcelCellSelectionModel*/
 		this.selModel = new Ext.ux.ExcelCellSelectionModel();
 		this.addListener('render',this.addKeyMap, this);
 	}, 	
 	addKeyMap:function(){
    	var thisGrid = this;
    	this.body.on("mouseover", this.onMouseOver, this);
    	this.body.on("mouseup", this.onMouseUp, this);
    	Ext.DomQuery.selectNode('div[class*=x-grid3-scroller]', this.getEl().dom).style.overflowX='hidden';
	 	// map multiple keys to multiple actions by strings and array of codes	 	
	 	new Ext.KeyMap(Ext.DomQuery.selectNode('div[class*=x-grid3-scroller]', this.getEl().dom).id, [{
	        key: "c",
	        ctrl:true,
	        fn: function(){	        
				thisGrid.copyToClipBoard(thisGrid.getSelectionModel().getSelectedCellRange());
			}
	    },{
	    	key: "v",
	        ctrl:true,
	        fn: function(){ 				        	
	        	 thisGrid.pasteFromClipBoard();
			}
	    }]);
	},
	onMouseOver:function(e){
		this.processEvent("mouseover", e);
	},
	onMouseUp:function(e){
		this.processEvent("mouseup", e);
	}, 
	copyToClipBoard:function(rows){
    	this.collectGridData(rows);
    	if( window.clipboardData && clipboardData.setData )	{
			clipboardData.setData("text", this.tsvData);
		} else {
			var hiddentextarea = this.getHiddenTextArea();
			hiddentextarea.dom.value = this.tsvData; 
	    	hiddentextarea.focus();
	        hiddentextarea.dom.setSelectionRange(0, hiddentextarea.dom.value.length);			
		}
    },
    collectGridData:function(cr){        	
        var row1 		= cr[0], col1 = cr[1], row2 = cr[2], col2=cr[3];
        this.tsvData 	="";
        var rowTsv		="";
        for(var r = row1; r<= row2; r++){
        	if(this.tsvData!=""){
        	  	this.tsvData +="\n";
        	}
        	rowTsv	= "";
        	for(var c = col1; c<= col2; c++){
        		if(rowTsv!=""){
	        	  	rowTsv+="\t";
	        	}
        	  	rowTsv += this.store.getAt(r).get( this.store.fields.itemAt(c).name);
        	}
        	this.tsvData +=rowTsv;
    	}
    	return this.tsvData;        
	},
		
	pasteFromClipBoard:function(){        
    	var hiddentextarea = this.getHiddenTextArea();
		hiddentextarea.dom.value =""; 
    	hiddentextarea.focus();
		       		
    },	
    updateGridData:function(){
    	var Record 			= Ext.data.Record.create(this.store.fields.items);        	
    	var tsvData 		= this.hiddentextarea.getValue();        
    	tsvData				= tsvData.split("\n");
    	var column			= [];
    	var cr 				= this.getSelectionModel().getSelectedCellRange();
		var nextIndex 		= cr[0];
		if( tsvData[0].split("\t").length==1 && ( (tsvData.length==1) || (tsvData.length==2  && tsvData[1].trim()== ""))){//if only one cell in clipboard data, block fill process (i.e. copy a cell, then select a group of cells to paste)
			for( var rowIndex = cr[0]; rowIndex<= cr[2]; rowIndex++){
				for( var columnIndex = cr[1]; columnIndex<= cr[3]; columnIndex++){
					this.store.getAt(rowIndex).set( this.store.fields.itemAt(columnIndex).name, tsvData[0] );
				}
			}
		}else{   		    		
			var gridTotalRows	= this.store.getCount();
			for(var rowIndex = 0; rowIndex < tsvData.length; rowIndex++ ){
				if( tsvData[rowIndex].trim()== "" ){
					continue;
				}
				columns	= tsvData[rowIndex].split("\t");
				if( nextIndex > gridTotalRows-1 ){
					var NewRecord 	= new Record({});        			
					this.stopEditing();        			
					this.store.insert(nextIndex, NewRecord);						
				}
				pasteColumnIndex = cr[1];				        		
				for(var columnIndex=0; columnIndex < columns.length; columnIndex++ ){
					this.store.getAt(nextIndex).set( this.store.fields.itemAt(pasteColumnIndex).name, columns[columnIndex] );
					pasteColumnIndex++;
				}
				nextIndex++;
			}
		}
    	this.hiddentextarea.blur();
    },
    getHiddenTextArea:function(){
		if(!this.hiddentextarea){
    		this.hiddentextarea = new Ext.Element(document.createElement('textarea'));        	
    		
    		//this.hiddentextarea.setStyle('left','-1000px');
			this.hiddentextarea.setStyle('border','2px solid #ff0000');
			this.hiddentextarea.setStyle('position','absolute');
			//this.hiddentextarea.setStyle('top','-0px');
			this.hiddentextarea.setStyle('z-index','-1');
			this.hiddentextarea.setStyle('width','100px');
			this.hiddentextarea.setStyle('height','30px');
			
    		this.hiddentextarea.addListener('keyup', this.updateGridData, this);
    		Ext.get(this.getEl().dom.firstChild).appendChild(this.hiddentextarea.dom);
    	}
    	return this.hiddentextarea;
    }
	
});
Ext.reg('editorPasteCopyGrid', Ext.ux.EditorPasteCopyGridPanel);

Ext.ux.CheckColumn = function(config) {
	Ext.apply(this, config);
	if (!this.id) {
		this.id = Ext.id();
	}
	this.renderer = this.renderer.createDelegate(this);
};

Ext.ux.CheckColumn.prototype = {
	init : function(grid) {
		this.grid = grid;
		this.grid.on('render', function() {
					var view = this.grid.getView();
					view.mainBody.on('mousedown', this.onMouseDown, this);
				}, this);
	},
	onMouseDown : function(e, t) {
     //   alert(t.className)
		if (t.className && t.className.indexOf('x-grid3-cc-' + this.id) != -1) {
			e.stopEvent();
			var index = this.grid.getView().findRowIndex(t);
			var record = this.grid.store.getAt(index);
			record.set(this.dataIndex, !record.data[this.dataIndex]);
		}
//            var hd = Ext.fly(t.parentNode);
//            var isChecked = hd.hasClass('x-grid3-hd-checker-on');
//            if(isChecked){
//                hd.removeClass('x-grid3-hd-checker-on');
//               // this.clearSelections();
//            }else{
//                hd.addClass('x-grid3-hd-checker-on');
//               // this.selectAll();
//            }
       
	},

	renderer : function(v, p, record) {
		p.css += ' x-grid3-check-col-td';
		return '<div class="x-grid3-check-col' + (v ? '-on' : '')
				+ ' x-grid3-cc-' + this.id + '">&#160;</div>';
	}
};